<?php

namespace app\index\controller;

use think\Controller;
use think\Db;

/**
 * 任务计划控制器
 **/
class Plan extends Controller
{
    public function monitorCrontabLog()
    {
        $this->checkIndexStatus();
        $this->checkNewsStatus();
        $this->checkLiveStatus();
    }
    
    /**
     * crontab_log表 记录 任务计划执行 监测结果
     * */
    public function logCrontab($type, $status, $course_id = 0)
    {
        $time = time();
        $date = date('Y-m-d');
        $Hi = date('H:i');
        
        $siren_config = getSirenConfig();
        
        if ($siren_config && ($Hi >= $siren_config['start_time'] && $Hi <= $siren_config['end_time'])) {
            // 查找最新的一条记录
            $info = Db::name('crontab_log')->where(['type' => $type, 'course_id' => $course_id, 'date' => $date])->order('id desc')->find();
            if ($info) {
                if ($status == 0) {
                    // 监测异常
                    
                    $err_count = $info['err_count'];// 上一次的连续监测错误次数
                    // 本次提醒时间间隔
                    $remind_time_range = $siren_config['siren_time_gap'][$err_count > 0 ? $err_count - 1 : $err_count];
                    
                    // 距离上次异常间隔时长
                    $prev_keep_time = $time - ($info['siren_time'] ?: 0);
                    
                    if ($remind_time_range && $prev_keep_time / 60 >= $remind_time_range) {
                        // 查找第一次异常的预警时间（未处理）
                        $sms_where = ['type' => $type, 'course_id' => $course_id, 'date' => $date, 'is_do' => 0];
                        $first_siren_time = Db::name('crontab_log')->where($sms_where)->order('id asc')->value('siren_time');
                        
                        $keep_time = $time - $first_siren_time;
                        // 记录监测异常
                        $data = [
                            'type' => $type,
                            'course_id' => $course_id,
                            'siren_time' => $time,
                            'status' => $status,
                            'err_count' => $err_count + 1,
                            'keep_time' => $keep_time,
                            'date' => $date
                        ];
                        $id = Db::name('crontab_log')->insertGetId($data);
                        
                        // 处理短信发送
                        $sms_siren = $siren_config['sms_siren'];
                        if ($sms_siren) {
                            // 查找当天最近一条正常的预警记录
                            $true_id = Db::name('crontab_log')->where(['type' => $type, 'course_id' => $course_id, 'date' => $date, 'status' => 1])->order('id desc')->value('id');
                            if ($true_id) $sms_where['id'] = ['gt', $true_id];
                            
                            // 查询该资源监测过程预警是否发送过短信
                            $sms_where['is_send_sms'] = 1;
                            $sms_count = Db::name('crontab_log')->where($sms_where)->count();
                            
                            $sms_mobile = $siren_config['sms_mobile'];
                            if ($first_siren_time && $keep_time >= $sms_siren * 60 && $sms_count == 0 && $sms_mobile) {
                                // 发送短信
                                Db::name('crontab_log')->where(['id' => $id])->setField('is_send_sms', 1);
                                
                                $type = $info['type'];
                                $is_app = false;
                                if ($type != 1) {
                                    if ($type == 2) {
                                        $db = 'news';
                                    } elseif ($type == 3 || $type == 4) {
                                        $db = 'live';
                                    }
                                    
                                    if ($db) $is_app = Db::name($db)->where(['id' => $info['course_id']])->value('is_app');
                                }
                                
                                sendSms($siren_config['sms_mobile'], $type, $is_app);
                            }
                        }
                    }
                } else {
                    // 监测正常
                    $data = [
                        'type' => $type,
                        'course_id' => $course_id,
                        'siren_time' => $time,
                        'status' => $status,
                        'err_count' => 0,
                        'keep_time' => 0,
                        'date' => $date
                    ];
                    Db::name('crontab_log')->insert($data);
                }
            } else {
                // 今日对于该$type还没有记录
                
                if ($status == 0) {
                    // 记录今日对于该$type的第一条异常记录
                    $data = [
                        'type' => $type,
                        'course_id' => $course_id,
                        'siren_time' => $time,
                        'status' => $status,
                        'err_count' => 1,
                        'keep_time' => 0,
                        'date' => $date
                    ];
                    $id = Db::name('crontab_log')->insertGetId($data);
                }
            }
        }
        
        return $id ?: 0;
    }
    
    // 监测首页是否正常
    public function checkIndexStatus()
    {
        $url = 'https://www.xntv.tv';
        $code = headerGetCode($url);
        
        $time = time();
        
        Db::startTrans();
        try {
            $status = $code == 200 ? 1 : 0;
            
            // 添加预警数据
            $crontab_log_id = $this->logCrontab(1, $status);
            
            $data = [
                'style' => 0,
                'status' => $status,
                'check_time' => $time,
                'crontab_log_id' => $crontab_log_id
            ];
            Db::name('check_index_log')->insert($data);
            
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
        }
    }
    
    // 监测新闻是否正常
    public function checkNewsStatus()
    {
        $time = time();
        
        Db::startTrans();
        try {
            $start_date = getAgoDate(-2);
            $where['publish_time'] = ['egt', $start_date];
            
            $news_list = Db::name('news')->field('id,url,status,is_app,content')->where($where)->select();
            if ($news_list) {
                $check_news_log_data = [];
                foreach ($news_list as &$v) {
                    if ($url = $v['url']) {
                        $code = headerGetCode($url);
                        
                        // 添加预警数据
                        $crontab_log_id = $this->logCrontab(2, $code == 200 ? 1 : 0, $v['id']);
                        
                        $data = [
                            'news_id' => $v['id'],
                            'terminal' => $v['is_app'] == 0 ? 1 : 2,
                            'check_time' => $time,
                            'crontab_log_id' => $crontab_log_id
                        ];
                        
                        if ($code == 200) {
                            if ($v['status'] == 0) Db::name('news')->where(['id' => $v['id']])->setField('status', 1);
                            
                            $data['status'] = 1;
                            
                            $data['html_content'] = $v['content'];
                            $data['log_file_path'] = '';
                        } else {
                            if ($v['status'] == 1) Db::name('news')->where(['id' => $v['id']])->setField('status', 0);
                            
                            $data['status'] = 0;
                            
                            $data['html_content'] = '';
                            
                            // 添加错误日志文件
                            $dir = './error_log/news/' . date('Y-m-d');
                            if (!is_dir($dir)) mkdir($dir);
                            $log_file_path = $dir . '/' . $time . rand(100, 999) . $v['id'] . '.txt';
                            file_put_contents($log_file_path, errorCodeDesc($url, $code));
                            $data['log_file_path'] = substr($log_file_path, 1);
                        }
                        
                        $check_news_log_data[] = $data;
                    }
                }
                Db::name('check_news_log')->insertAll($check_news_log_data);
            }
            
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
        }
    }
    
    // 监测音视频是否正常（网页端）
    public function checkLiveStatus()
    {
        $time = time();
        
        Db::startTrans();
        try {
            $start_date = getAgoDate(-6);
            
            // 异常音视频数据监测
            $err_live_list = Db::name('live')->where(['publish_time' => ['egt', $start_date], 'status' => 0, 'type_id' => ['IN', '1,2,3,4,5,6']])->select();
            $this->checkLive($err_live_list);
            
            // 正常的随机抽取 X 条数据进行监测
            $where = " status = 1 AND publish_time >= '" . $start_date . "' AND type_id IN ('1,2,3,4,5,6') ";
            $sql = "SELECT * FROM monitor_live WHERE id >= ( ( SELECT MAX(id) FROM monitor_live WHERE " . $where . " ) - ( SELECT MIN(id) FROM monitor_live WHERE " . $where . " ) ) * RAND() + ( SELECT MIN(id) FROM monitor_live WHERE " . $where . " ) LIMIT 10;";
            $normal_live_list = Db::name('live')->query($sql);
            $this->checkLive($normal_live_list);
            
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
        }
    }
    
    public function checkLive($live_list)
    {
        $time = time();
        if ($live_list) {
            $check_live_log_data = [];
            foreach ($live_list as &$v) {
                if ($url = $v['url']) {
                    $code = headerGetCode($url);
                    
                    // 1：视频，2：音频
                    $type = in_array($v['type_id'], [1, 2]) ? 1 : 2;
                    
                    // 添加预警数据
                    $crontab_log_id = $this->logCrontab($type == 1 ? 3 : 4, $code == 200 ? 1 : 0, $v['id']);
                    
                    $data = [
                        'type' => $type,
                        'live_id' => $v['id'],
                        'check_time' => $time,
                        'crontab_log_id' => $crontab_log_id
                    ];
                    
                    if ($code == 200) {
                        if ($v['status'] == 0) Db::name('live')->where(['id' => $v['id']])->setField('status', 1);
                        
                        $data['status'] = 1;
                    } else {
                        if ($v['status'] == 1) Db::name('live')->where(['id' => $v['id']])->setField('status', 0);
                        
                        $data['status'] = 0;
                        
                        // 添加错误日志文件
                        $dir = './error_log/live/' . date('Y-m-d');
                        if (!is_dir($dir)) mkdir($dir);
                        $log_file_path = $dir . '/' . $time . rand(100, 999) . $v['id'] . 'txt';
                        file_put_contents($log_file_path, errorCodeDesc($url, $code));
                        $data['log_file_path'] = $log_file_path;
                    }
                    
                    $check_live_log_data[] = $data;
                }
            }
            Db::name('check_live_log')->insertAll($check_live_log_data);
        }
    }
    
    /**
     * 监测今日是否更新网站新闻
     * */
    public function isUpdateWebNews()
    {
        $date = date('Y-m-d') . ' 00:00:00';
        $count = Db::name('news')->where(['is_app' => 0, 'publish_time' => ['egt', $date]])->count();
        if ($count == 0) {
            $siren_config = getSirenConfig();
            $mobile = $siren_config['sms_mobile'];
            if ($mobile) sendSms($mobile, 5);
        }
    }
    
    /**
     * 备份新闻监测记录
     * */
    public function bakNewsLogData()
    {
        $db = 'monitor';
        $table = 'check_news_log';
        $bak_table = $db . '_' . $table . '_bak_' . date('Ymd');
        
        $conn = mysqli_connect(config('database.hostname'), config('database.username'), config('database.password'));
        if ($conn) {
            $create_table_sql = "
                CREATE TABLE `". $bak_table ."`  (
                  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
                  `user_id` int(10) NULL DEFAULT 0 COMMENT '操作人用户id',
                  `news_id` int(10) NULL DEFAULT 0 COMMENT '新闻id',
                  `terminal` int(10) NULL DEFAULT 1 COMMENT '终端；1：网页端，2：app端',
                  `log_file_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '日志文件位置',
                  `status` int(10) NULL DEFAULT 1 COMMENT '状态；0：异常，1：正常',
                  `style` int(10) NULL DEFAULT 0 COMMENT '0：未处理，1：已查看，2：已处理，3：暂不处理',
                  `html_content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '当时监测请求的html内容',
                  `update_time` int(10) NULL DEFAULT 0 COMMENT '修改时间',
                  `check_time` int(10) NULL DEFAULT 0 COMMENT '创建时间',
                  `crontab_log_id` int(10) NULL DEFAULT 0 COMMENT '预警id；当处理异常存在这个预警id时，需要修改crontab_log表中对应数据为已处理状态',
                  PRIMARY KEY (`id`) USING BTREE
                ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '新闻监测记录结果表' ROW_FORMAT = DYNAMIC;
            ";
            mysqli_select_db($conn, 'monitor');
            $res = mysqli_query($conn, $create_table_sql);
            if ($res) {
                mysqli_close($conn);
                
                Db::startTrans();
                try {
                    $end_date = date('Y-m-d', strtotime(getAgoDate(-3)));
                    $end_date_int = strtotime($end_date);//只保留这一天之前的数据
                    
                    $where['check_time'] = ['lt', $end_date_int];
                    $list = Db::name($table)->field('user_id,news_id,terminal,log_file_path,status,style,html_content,update_time,check_time,crontab_log_id')->where($where)->order('id asc')->select();
                    if($list){
                        $data = [];
                        foreach($list as &$v){
                            $data[] = $v;
                        }
                        if($data){
                            Db::table($bak_table)->data($data)->limit(100)->insertAll($data);
                        }
                    }
                    Db::name($table)->where($where)->delete();
                    
                    Db::commit();
                    file_put_contents(RUNTIME_PATH . '新闻监测数据备份成功', 1);
                }catch (\Exception $e){
                    Db::rollback();
                }
                
            }
        }
    }
    
    /**
     * 备份音视频监测记录
     * */
    public function bakLiveLogData()
    {
        $db = 'monitor';
        $table = 'check_live_log';
        $bak_table = $db . '_' . $table . '_bak_' . date('Ymd');
        
        $conn = mysqli_connect(config('database.hostname'), config('database.username'), config('database.password'));
        if ($conn) {
            $create_table_sql = "
                CREATE TABLE `". $bak_table ."` (
                  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
                  `user_id` int(10) DEFAULT '0' COMMENT '操作人用户id',
                  `live_id` int(10) DEFAULT '0' COMMENT '音视频id',
                  `terminal` int(10) DEFAULT '1' COMMENT '终端；1：网页端，2：app端',
                  `type` int(10) DEFAULT '1' COMMENT '1：视频，2：音频',
                  `log_file_path` varchar(255) DEFAULT '' COMMENT '日志文件位置',
                  `status` int(10) DEFAULT '1' COMMENT '状态；0：异常，1：正常',
                  `style` int(10) DEFAULT '0' COMMENT '0：未处理，1：已查看，2：已处理，3：暂不处理',
                  `update_time` int(10) DEFAULT '0' COMMENT '修改时间',
                  `check_time` int(10) DEFAULT '0' COMMENT '监测时间',
                  `crontab_log_id` int(10) DEFAULT '0' COMMENT '预警id；当处理异常存在这个预警id时，需要修改crontab_log表中对应数据为已处理状态',
                  PRIMARY KEY (`id`)
                ) ENGINE=InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT='音视频监测记录结果表' ROW_FORMAT = DYNAMIC;
            ";
            mysqli_select_db($conn, 'monitor');
            $res = mysqli_query($conn, $create_table_sql);
            if ($res) {
                $res = mysqli_close($conn);
                Db::startTrans();
                try {
                    $end_date = date('Y-m-d', strtotime(getAgoDate(-3)));
                    $end_date_int = strtotime($end_date);//只保留这一天之前的数据
                    
                    $where['check_time'] = ['lt', $end_date_int];
                    $list = Db::name($table)->field('user_id,live_id,terminal,type,log_file_path,status,style,update_time,check_time,crontab_log_id')->where($where)->order('id asc')->select();
                    if($list){
                        $data = [];
                        foreach($list as &$v){
                            $data[] = $v;
                        }
                        if($data){
                            Db::table($bak_table)->data($data)->limit(100)->insertAll($data);
                        }
                    }
                    Db::name($table)->where($where)->delete();
                    
                    Db::commit();
                    file_put_contents(RUNTIME_PATH . '音视频监测数据备份成功', 1);
                }catch (\Exception $e){
                    Db::rollback();
                }
                
            }
        }
    }
    
    /**
     * 备份首页监测记录
     * */
    public function bakIndexLogData()
    {
        $db = 'monitor';
        $table = 'check_index_log';
        $bak_table = $db . '_' . $table . '_bak_' . date('Ymd');
        
        $conn = mysqli_connect(config('database.hostname'), config('database.username'), config('database.password'));
        if ($conn) {
            mysqli_select_db($conn, 'monitor');
            
            $create_table_sql = "
                CREATE TABLE `" . $bak_table . "` (
                  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
                  `user_id` int(10) NOT NULL DEFAULT '0' COMMENT '操作人用户id',
                  `style` int(10) NOT NULL DEFAULT '0' COMMENT '0：未处理，1：已查看，2：已处理，3：暂不处理',
                  `status` int(10) NOT NULL DEFAULT '1' COMMENT '状态；0：异常，1：正常',
                  `update_time` int(10) NOT NULL DEFAULT '0' COMMENT '修改时间',
                  `check_time` int(10) NOT NULL DEFAULT '0' COMMENT '监测时间',
                  `crontab_log_id` int(10) NOT NULL DEFAULT '0' COMMENT '预警id；当处理异常存在这个预警id时，需要修改crontab_log表中对应数据为已处理状态',
                  PRIMARY KEY (`id`)
                ) ENGINE=InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT='首页监测记录' ROW_FORMAT = DYNAMIC;
            ";
            
            $res = mysqli_query($conn, $create_table_sql);
            if ($res) {
                mysqli_close($conn);
                
                Db::startTrans();
                try {
                    $end_date = date('Y-m-d', strtotime(getAgoDate(-3)));
                    $end_date_int = strtotime($end_date);//只保留这一天之前的数据
                    
                    $where['check_time'] = ['lt', $end_date_int];
                    $list = Db::name($table)->field('user_id,style,status,update_time,check_time,crontab_log_id')->where($where)->order('id asc')->select();
                    if($list){
                        $data = [];
                        foreach($list as &$v){
                            $data[] = $v;
                        }
                        if($data){
                            Db::table($bak_table)->data($data)->limit(100)->insertAll($data);
                        }
                    }
                    Db::name($table)->where($where)->delete();
                    
                    Db::commit();
                    file_put_contents(RUNTIME_PATH . '首页监测数据备份成功', 1);
                }catch (\Exception $e){
                    Db::rollback();
                }
            }
        }
    }
    
}